package Thread;
/**可重入锁的实现
 * 1.在锁的内部记录当前哪个线程持有的锁，后续每次加锁都要进行判定
 * 2.通过计数器，记录当前加锁的次数，从而确定何时真正加锁*/
public class demo19_1 {
    private Thread owner; // 当前持有锁的线程
    private int count;    // 锁的计数器

    // synchronized 关键字确保方法在同一时间只能被一个线程访问
    public synchronized void lock() {
        // 获取当前线程
        Thread currentThread = Thread.currentThread();
        if (currentThread == owner) {
            // 如果当前线程已经持有锁，增加计数器
            count++;
        } else {
            // 如果当前线程没有持有锁，等待直到锁被释放
            while (owner != null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException(e);
                }
            }
            // 当前线程获取锁
            owner = currentThread;
            count = 1;
        }
    }

    public synchronized void unlock() {
        if (Thread.currentThread() == owner) {
            // 如果当前线程持有锁，减少计数器
            count--;
            if (count == 0) {
                // 如果计数器为0，释放锁
                owner = null;
                notify();
            }
        } else {
            // 当前线程没有持有锁抛异常
            throw new IllegalMonitorStateException("当前线程不持有锁");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        demo19_1 lock = new demo19_1();

        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("线程t1拿到锁");
                lock.lock();
                try {
                    System.out.println("线程t1再一次拿到锁");
                } finally {
                    lock.unlock();
                }
            } finally {
                lock.unlock();
            }
        });

        Thread t2 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("线程t2拿到锁");
            } finally {
                lock.unlock();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();
    }
}